package org.anderground.editor.gui.view.android;

import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.Observable;

import javax.swing.ButtonGroup;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;

import org.anderground.editor.gui.view.MetroView;

@SuppressWarnings("serial")
public class AndroidDrawerView extends MetroView {
	private AndroidDrawerPanel drawerPanel;
	private float minScale;
	private Point lastDragPoint = new Point();

	public AndroidDrawerView() {
		drawerPanel = new AndroidDrawerPanel();
		this.setLayout(new GridLayout());
		this.add(drawerPanel);

		this.addMouseListener(new MapScrollAuxiliaryListener());
		this.addMouseMotionListener(new MapScrollListener());
		this.addMouseWheelListener(new MapScaleListener());
		this.addMouseListener(new PopupMenuListener());

	}

	@Override
	public void update(Observable o, Object arg) {
		drawerPanel.updateModel();
		drawerPanel.repaint();
	}

	private class MapScaleListener implements MouseWheelListener {
		private final float SCALE_STEP = 1.1f;

		@Override
		public void mouseWheelMoved(MouseWheelEvent arg0) {
			float scaleShift = (arg0.getWheelRotation() < 0) ? SCALE_STEP
					: 1 / SCALE_STEP;
			float currScale = drawerPanel.getScale();
			if (currScale * scaleShift > minScale)
				drawerPanel.setScale(currScale * scaleShift);
			repaint();

		}

	}

	private class MapScrollListener implements MouseMotionListener {
		public void mouseDragged(MouseEvent arg0) {
			int dx = arg0.getPoint().x - lastDragPoint.x;
			int dy = arg0.getPoint().y - lastDragPoint.y;
			drawerPanel.shift(dx, dy);
			lastDragPoint = new Point(arg0.getPoint().x, arg0.getPoint().y);

			drawerPanel.repaint();
		}

		public void mouseMoved(MouseEvent arg0) {

		}

	}

	private class MapScrollAuxiliaryListener extends MouseAdapter {
		@Override
		public void mousePressed(MouseEvent arg0) {
			lastDragPoint = arg0.getPoint();

		}

		@Override
		public void mouseReleased(MouseEvent arg0) {
			lastDragPoint = null;

		}
	}

	private class AndroidViewPopupMenu extends JPopupMenu {

		public AndroidViewPopupMenu() {
			ButtonGroup drawersGroup = new ButtonGroup();
			for (final DrawersRegistry.DrawerEntry drawerEntry : DrawersRegistry
					.getEntries()) {
				JRadioButtonMenuItem rbMenuItem;
				rbMenuItem = new JRadioButtonMenuItem(drawerEntry.getName());
				rbMenuItem.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						drawerPanel
								.setDrawerClass(drawerEntry.getDrawerClass());
					}
				});
				if (drawerEntry.getDrawerClass().equals(
						drawerPanel.getDrawerClass())) {
					rbMenuItem.setSelected(true);
				}
				drawersGroup.add(rbMenuItem);
				add(rbMenuItem);
			}
		}

	}

	private class PopupMenuListener extends MouseAdapter {
		public PopupMenuListener() {
		}

		@Override
		public void mouseReleased(MouseEvent mouseEvent) {
			if (mouseEvent.isPopupTrigger()) {
				new AndroidViewPopupMenu().show(mouseEvent.getComponent(),
						mouseEvent.getX(), mouseEvent.getY());
			}
		}

		@Override
		public void mousePressed(MouseEvent mouseEvent) {
			if (mouseEvent.isPopupTrigger()) {
				new AndroidViewPopupMenu().show(mouseEvent.getComponent(),
						mouseEvent.getX(), mouseEvent.getY());
			}
		}

	}

	@Override
	public void afterPanelInit() {
		drawerPanel.reset();
		Rectangle mapBounds = getMapBounds();
		drawerPanel.shift(this.getWidth() / 2, this.getHeight() / 2);
		float scaleX = (float) (this.getHeight() / mapBounds.getHeight());
		float scaleY = (float) (this.getWidth() / mapBounds.getWidth());
		float finalScale = Math.min(scaleX, scaleY);
		drawerPanel.setScale(finalScale);
		drawerPanel.shift(-(int) (mapBounds.getCenterX() * finalScale),
				-(int) (mapBounds.getCenterY() * finalScale));
		this.minScale = finalScale * 0.01f;

	}

}
